﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Sublimation.Behaviours
{
    public class UnitCohesionBehaviour : Behaviour
    {
        protected WorldProperties worldProperties;
        protected Unit owner;
        protected float weight;
        public float getWeight() { return this.weight; }
        protected float separationDistance;

        public UnitCohesionBehaviour(WorldProperties worldProperties, Unit owner, float weight, float separationDistance)
        {
            this.worldProperties = worldProperties;
            this.owner = owner;
            this.weight = weight;
            this.separationDistance = separationDistance;
        }

        // lets just check this behaviour every X updates - it doesn't change that often and it's kinda heavy
        private Vector2 lastResult;
        private int tickCount = 0;
        private const int TICKS_BETWEEN_UPDATES = 4;

        private const int NUMBER_OF_REACTIONS = 10;
        public Vector2 RunBehaviour()
        {
            // move closer to friendly units
            if (tickCount == 0)
            {
                tickCount = TICKS_BETWEEN_UPDATES;

                Vector2 result = Vector2.Zero;

                int unitsInSightRangeCount = 0;

                if (owner is EnemyUnit)
                {
                    foreach (EnemyUnit unit in worldProperties.Enemies)
                    {
                        if (Object.ReferenceEquals(owner, unit)) continue;
                        if (Vector2.Distance(unit.Position, owner.Position) <= owner.AISightRange)
                        {
                            result += EvaluateAgainst(unit);
                            unitsInSightRangeCount++;
                            if (unitsInSightRangeCount > NUMBER_OF_REACTIONS) break;
                        }
                    }
                }
                if (owner is FriendlyUnit)
                {
                    foreach (Player player in worldProperties.Players)
                    {
                        foreach (FriendlyUnit unit in player.Units)
                        {
                            if (Object.ReferenceEquals(owner, unit)) continue;
                            if (Vector2.Distance(unit.Position, owner.Position) <= owner.AISightRange)
                            {
                                result += EvaluateAgainst(unit);
                                unitsInSightRangeCount++;
                                if (unitsInSightRangeCount > NUMBER_OF_REACTIONS) break;
                            }
                        }
                    }
                }

                if (unitsInSightRangeCount > 1) result /= unitsInSightRangeCount;

                lastResult = result * weight;
            }

            tickCount--;
            
            return lastResult;
        }

        //XXX: I culled this for performance reasons
        protected Vector2 EvaluateAgainst(Unit other)
        {
            // if they arent already too close
            //if (Vector2.Distance(other.Position, owner.Position) > separationDistance)
            //{
                // move in the direction of the other unit, more the further away it is
                Vector2 result = Vector2.Normalize(other.Position - owner.Position) *
                    (float)Math.Pow((double)
                        (Vector2.Distance(other.Position, owner.Position) - separationDistance) / (owner.AISightRange - separationDistance)
                        , 2);

                // clamp to max speed
                if (result.Length() > owner.MaxSpeed) return Vector2.Normalize(result) * owner.MaxSpeed;

                return result;
  //          }
//            return Vector2.Zero;
        }
    }
}
